package br.com.velp.sudecap.daoimpl;

import br.com.velp.sudecap.comum.SpringConstants;
import br.com.velp.sudecap.dao.UsuarioDAO;
import br.com.velp.sudecap.dto.UsuarioParametrosConsultaDTO;
import br.com.velp.sudecap.dto.UsuarioResultadoConsultaDTO;
import br.com.velp.sudecap.entidade.*;
import br.com.velp.sudecap.enumerator.FuncionalidadeEnum;
import br.com.velp.sudecap.service.LogEventoService;
import br.com.velp.sudecap.util.ConsultaFiltros;
import br.com.velp.sudecap.util.CriptografiaUtil;
import br.com.velp.sudecap.util.NormalizacaoUtil;
import java.util.List;
import org.apache.commons.lang.StringUtils;
import org.hibernate.*;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.hibernate.transform.Transformers;
import org.hibernate.type.BooleanType;
import org.hibernate.type.IntegerType;
import org.hibernate.type.LongType;
import org.hibernate.type.StringType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Repository;

/**
 * <sumario> 
 * <objetivo> "Rastreabilidade" </objetivo> 
 * <autor> EDUARDO SANTOS DE OLIVEIRA </autor> 
 * <versao>1.0.0.0</versao> 
 * <data_criacao> 17.10.2012 </data_criacao> 
 * <data_ultima_alteracao> N/A </data_ultima_alteracao>
 * <requisitos_afetados> RF001.02 - Listar Usuários / RF001.03 - Cadastrar Usuários </requisitos_afetados> 
 * <descricao> Implementação da Interface Responsável Pelas Operações 
 *             de CRUD Referentes ao Contexto de Usuários
 * </descricao> 
 * </sumario>
 */
@Repository("usuarioDAO")
@Lazy(SpringConstants.LAZY_BEANS)
public class UsuarioDAOImpl implements UsuarioDAO {

    public static final Long serialVersionUID = 1L;
    
    @Autowired
    private LogEventoService logEventoService;                                    
    
    @Autowired
    private SessionFactory sessionFactory;
    
    @Override
    public int contarUsuarios(UsuarioParametrosConsultaDTO parametros) {
        
        ConsultaFiltros consultaFiltro = new ConsultaFiltros();
        
        StringBuilder consulta = new StringBuilder();
        consulta.append("select count(distinct usu.id_usu) as qtdUsuarios ");
	adicionarParametrosConsulta(consulta, parametros, consultaFiltro);
        
        SQLQuery query = getSession().createSQLQuery(consulta.toString());
        query.setProperties(consultaFiltro.getParametros());
        query.addScalar("qtdUsuarios", LongType.INSTANCE);
        
	return ((Long) query.uniqueResult()).intValue();
        
    }

    @Override
    public List<Usuario> buscarUsuariosPaginados(int firstResult, int maxResults,
	    UsuarioParametrosConsultaDTO parametros, Order order) {

        ConsultaFiltros consultaFiltro = new ConsultaFiltros();
        
        StringBuilder consulta = new StringBuilder();
        consulta.append("select distinct ");
        consulta.append("usu.id_usu as id, ");
        consulta.append("usu.matricula as matricula, ");
        consulta.append("usu.nome as nome, ");
        consulta.append("usu.login as login, ");
        consulta.append("usu.flg_ativo as ativo ");
        
	adicionarParametrosConsulta(consulta, parametros, consultaFiltro);
        
        if(order != null){
            consulta.append("order by ").append(order.toString());
        }else{
            consulta.append("order by usu.nome ");
        }
        
        SQLQuery query = getSession().createSQLQuery(consulta.toString());
        query.setResultTransformer(Transformers.aliasToBean(Usuario.class));
        query.setProperties(consultaFiltro.getParametros());
        query.addScalar("id", LongType.INSTANCE);
        query.addScalar("matricula", IntegerType.INSTANCE);
        query.addScalar("nome", StringType.INSTANCE);
        query.addScalar("login", StringType.INSTANCE);
        query.addScalar("ativo", BooleanType.INSTANCE);
        
        if(firstResult > 0){
            query.setFirstResult(firstResult);
        }
        
        if(maxResults > 0){
            query.setMaxResults(maxResults);
        }
        
	return query.list();

    }

    @Override
    public Long salvar(Usuario value) {
	
        Long id = (Long) getSession().save(value);
	getSession().flush();
        
        this.logEventoService.registrarLogEventoCadastro(
                id, FuncionalidadeEnum.USUARIO, "consultarUsuario");                                                                                                                              
        
	return id;
        
    }

    @Override
    public void atualizar(Usuario value) {
	
        getSession().update(value);
	getSession().flush();
        
    }

    @Override
    public Usuario obterPorId(Long id) {
	
        return (Usuario) getSession().get(Usuario.class, id);
        
    }

    @Override
    public void excluir(Usuario value) {
        
        value = obterPorId(value.getId());
	getSession().delete(value);
	getSession().flush();
        
    }

    private void adicionarParametrosConsulta(StringBuilder consulta, UsuarioParametrosConsultaDTO parametros, 
            ConsultaFiltros consultaFiltro) {
        
        NormalizacaoUtil.normalizarEntidade(parametros);
        
        consulta.append("from usuario usu, direito_usu direito ");
        consulta.append("where usu.id_usu = direito.id_usu(+) ");
        
        consultaFiltro.addFiltroSqlEqual("usu.flg_ativo", "status", parametros.getStatus());
        consultaFiltro.addFiltroSqlEqual("usu.matricula", "matricula", parametros.getMatricula());
        consultaFiltro.addFiltroSqlLikeAnyWhere("usu.nome", "nome", parametros.getNome());
        consultaFiltro.addFiltroSqlEqual("direito.cod_grupo_usu", "idGrupo", parametros.getIdGrupo());
        consultaFiltro.addFiltroSqlEqual("usu.id_usu", "id", parametros.getIdUsuarioFiltro());
        consultaFiltro.addFiltroSqlLikeStart("usu.login", "login", parametros.getLogin());
        
        consulta.append(consultaFiltro.getFiltros());
        
    }

    @Override
    public Usuario recuperarUsuarioPorLoginSenha(String login, String senha) {
        
        StringBuilder consulta = new StringBuilder();
        
        consulta.append("select id as id, ");
        consulta.append("matricula as matricula, ");
        consulta.append("nome as nome, ");
        consulta.append("login as login, ");
        consulta.append("senha as senha, ");
        consulta.append("cpf as cpf, ");
        consulta.append("ativo as ativo ");        
        consulta.append("from Usuario ");
        consulta.append("where lower(login) = lower(:login) ");
        consulta.append("and senha = :senha ");
        
        Query query = getSession().createQuery(consulta.toString());
        query.setResultTransformer(Transformers.aliasToBean(Usuario.class));
        
        query.setParameter("login", login);
        query.setParameter("senha", CriptografiaUtil.criptografar(CriptografiaUtil.ALGORITMO.MD5, senha));
        
	return (Usuario) query.uniqueResult();
        
    }
    
    @Override
    public UsuarioResultadoConsultaDTO recuperarUsuarioDTOPorLoginSenha(String login, String senha) {
        
        StringBuilder consulta = new StringBuilder();
        
        consulta.append("select id as id, ");
        consulta.append("matricula as matricula, ");
        consulta.append("nome as nome, ");
        consulta.append("login as login, ");
        consulta.append("senha as senha, ");
        consulta.append("cpf as cpf, ");
        consulta.append("ativo as ativo ");        
        consulta.append("from Usuario ");
        consulta.append("where lower(login) = lower(:login) ");
        consulta.append("and senha = :senha ");
        
        Query query = getSession().createQuery(consulta.toString());
        query.setResultTransformer(Transformers.aliasToBean(UsuarioResultadoConsultaDTO.class));
        
        query.setParameter("login", login);
        query.setParameter("senha", CriptografiaUtil.criptografar(CriptografiaUtil.ALGORITMO.MD5, senha));
        
	return (UsuarioResultadoConsultaDTO) query.uniqueResult();
        
    }    

    @Override
    public List<DireitoSistema> recuperarPrivilegiosUsuario(Usuario usuario, String sistema) {

	StringBuilder consulta = new StringBuilder();

	consulta.append(" select dir.COD_DIREITO as id, ");
	consulta.append(" dir.DESC_DIREITO as descricao, ");
	consulta.append(" dir.MODULO as modulo, ");
	consulta.append(" dir.INTERFACE as funcionalidade ");
	consulta.append(" from DIREITO_SISTEMA dir ");
	consulta.append(" left join DIREITO_USU diu on (diu.COD_DIREITO = dir.COD_DIREITO) ");
	consulta.append(" where diu.ID_USU = :idUsuario ");
        
        if (StringUtils.isNotBlank(sistema)) {
            consulta.append(" and dir.sistema = :sistema ");
        }
        
	consulta.append(" union ");
	consulta.append(" select dir.COD_DIREITO as id, ");
	consulta.append(" dir.DESC_DIREITO as descricao, ");
	consulta.append(" dir.MODULO as modulo, ");
	consulta.append(" dir.INTERFACE as funcionalidade ");
	consulta.append(" from DIREITO_SISTEMA dir ");
	consulta.append(" left join DIREITO_GRUPO_USU dgu on dgu.COD_DIREITO = dir.COD_DIREITO ");
	consulta.append(" where dgu.COD_GRUPO_USU in ");
	consulta.append(" (select diu.COD_GRUPO_USU from DIREITO_USU diu where diu.ID_USU = :idUsuario) ");
        
        if (StringUtils.isNotBlank(sistema)) {
            consulta.append(" and dir.sistema = :sistema ");
        }

	SQLQuery query = getSession().createSQLQuery(consulta.toString());

	query.setParameter("idUsuario", usuario.getId());
        
        if (StringUtils.isNotBlank(sistema)) {
            query.setParameter("sistema", sistema);
        }
        
	query.addScalar("id", LongType.INSTANCE);
	query.addScalar("descricao", StringType.INSTANCE);
	query.addScalar("modulo", StringType.INSTANCE);
	query.addScalar("funcionalidade", StringType.INSTANCE);
	query.setResultTransformer(Transformers.aliasToBean(DireitoSistema.class));

	return query.list();

    }

    @Override
    public boolean usuarioJaCadastradoLogin(Usuario usuario) {
	
        Criteria criteria = getSession().createCriteria(Usuario.class);
	criteria.setProjection(Projections.rowCount());
	criteria.add(Restrictions.eq("login", usuario.getLogin()));
        
	if (usuario.getId() != null) {
	    criteria.add(Restrictions.ne("id", usuario.getId()));
	}
        
	return ((Long) criteria.uniqueResult()) > 0;
        
    }

    @Override
    public boolean usuarioJaCadastradoMatricula(Usuario usuario) {
	
        Criteria criteria = getSession().createCriteria(Usuario.class);
	criteria.setProjection(Projections.rowCount());
	criteria.add(Restrictions.eq("matricula", usuario.getMatricula()));
	
        if (usuario.getId() != null) {
	    criteria.add(Restrictions.ne("id", usuario.getId()));
	}
        
	return ((Long) criteria.uniqueResult()) > 0;
        
    }
    
    @Override
    public boolean usuarioJaCadastradoCpf(Usuario usuario){
        
        if(StringUtils.isBlank(usuario.getCpf())){
            return false;
        }
        
	Criteria criteria = getSession().createCriteria(Usuario.class);
	criteria.setProjection(Projections.rowCount());
	criteria.add(Restrictions.eq("cpf", usuario.getCpf()));
        
	if(usuario.getId() != null){
	    criteria.add(Restrictions.ne("id", usuario.getId()));
	}
        
	return ((Long) criteria.uniqueResult()) > 0;
        
    }

    @Override
    public boolean usuarioPresenteAuditoriaSistema(Usuario usuario, Class... classes) {
	
        try {
	    
            for (Class clazz : classes) {
                
		Criteria criteria = getSession().createCriteria(clazz);
		criteria.setProjection(Projections.rowCount());
		criteria.add(Restrictions.or(Restrictions.eq("idUsuarioCadastro", usuario.getId()), Restrictions.eq("idUsuarioAlteracao", usuario.getId())));
		
                int count = ((Long) criteria.uniqueResult()).intValue();
                
		if (count > 0) {
		    return true;
		}
                
	    }
            
	    return false;
            
	} catch (Exception e) {
            
	    return true;
            
	}
        
    }
    
    @Override
    public List<Diretoria> carregarTodasDiretorias(){
	
        return getSession().createCriteria(Diretoria.class).addOrder(Order.asc("nome")).list();
        
    }
    
    @Override
    public List<Local> carregarTodosLocais(){
	
        return getSession().createCriteria(Local.class).addOrder(Order.asc("nome")).list();
        
    }

    @Override
    public List<Setor> carregarTodosSetores(){
	
        return getSession().createCriteria(Setor.class).addOrder(Order.asc("nome")).list();
        
    }
    
    @Override
    public boolean senhaAlterada(Usuario usuario){
        
        Criteria criteria = getSession().createCriteria(Usuario.class);
        
        criteria.setProjection(Projections.rowCount());
        criteria.add(Restrictions.eq("id", usuario.getId()));
        criteria.add(Restrictions.eq("senha", CriptografiaUtil.criptografar(CriptografiaUtil.ALGORITMO.MD5, usuario.getSenha())));
        
        return ((Long) criteria.uniqueResult()).intValue() == 0;
        
    }
    
    @Override
    public List<Usuario> obterTodosUsuarios() {

        StringBuilder consulta = new StringBuilder();
        
        consulta.append("select id as id, ");
        consulta.append("nome as nome, ");
        consulta.append("login as login ");
        consulta.append("from Usuario ");
        consulta.append("order by login ");
        
        Query query = getSession().createQuery(consulta.toString());
        query.setResultTransformer(Transformers.aliasToBean(Usuario.class));
        
        return query.list();
        
    }
    
    public Session getSession(){
	
        return this.sessionFactory.getCurrentSession();
        
    }
    
}
